#coding=utf-8
'''
这个视频客流的数据管理模块，主要分为：
1.http协议上传数据到服务器
2.生成客流数据并将保存在设备文件系统中。
'''
from __future__ import division
import numpy as np
import math
import cv2
import platform
import profile
import math
import httplib
import urllib
import re
import time
import hashlib
import json
import os
import pickle
import multiprocessing as mp
import threading
import time
import Queue
from threading import Timer
import logging
import shutil
import renetlink
import requests
import parameter
import emailSend

#import multipart_encode
if parameter.UseingFlaskVideo == True:
    import flaskVideo

photoSaveFlag = False#拍照保存的标志，用于通知录像线程保存照片
checkNetFlag = False#检测网络状态标志
askPhotoCnt= 0

def is_json(str):
    try:
        json.loads(str)
    except ValueError:
        return False
    return True

class Protocol():
    '''
    @通信协议
    '''
    #versionOldURL = "/admin/mdh.action"#老版本上传数据的接口
    versionOldURL = "/admin/mdh.php"#老版本上传数据的接口
    PublicPortUri = "/zzb_v2/device2.php"
    SIGNStr = "mdheda8c1c5asd478as3a2sd3"

    def __init__(self,DEVID,url="wx.zhanzhibao.diyeasy.com.cn"):
        '''
        @协议初始化
        :param DEVID: 设备的ID
        :param PublicOrgan: 公共节点url
        '''
        print url
        self.DEVID = str(DEVID)  #设备id
        self.PublicOrgan = str(url)+":81"
        print 'This Dev Info:',self.DEVID,self.PublicOrgan

    def httpInit(self):
        '''
        @初始化hettp协议
        :return:
        '''
        #print  "HTTP Init Start"
        self.conn = httplib.HTTPConnection(self.PublicOrgan,timeout=30)
        #这个是公共节点的HTTP headr
        self.pulicHaders = \
            {"Content-type": "application/x-www-form-urlencoded",
             "Accept": "text/plain",
             "Connection":"Keep - Alive",
             "host": self.PublicOrgan,
             "User-Agent":'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36'}
        #print "HTTP Init Start End"

    def httpClose(self):
        '''
        @http关闭连接
        :return:
        '''
        self.conn.close()

    def httpRelink(self):
        self.httpClose()
        self.httpInit()

    def httpErrorProcess(self):
        '''
        http错误处理
        :return:
        '''
        try:
            global  checkNetFlag
            checkNetFlag = True
            #renetlink.systemNetStatusProcess()
            time.sleep(20)#暂停40S网络工作
        except Exception,e:
            print 'Net Status Process Error'

    def makeUrlCode(self, CMD, TAG1='', TAG2='', TAG3=''):
        '''
        @产生URL的数据部分代码用于http组装
        :param CMD:
        :param TAG1:
        :param TAG2:
        :param TAG3:
        :return:
        '''
        #return urllib.urlencode({'UID': self.UID, 'WAPID': '1d', 'DEVID': self.DEVID, 'CMD':str(CMD),'TAG1':str(TAG1),'TAG2':str(TAG2),'TAG3':str(TAG3),})
        print 'DEVID='+str(self.DEVID)+'&CMD='+str(CMD)+'&TAG1='+str(TAG1)+'&TAG2='+str(TAG2)+'&TAG3='+str(TAG3)+'&FORMATOUT=WAP'
        return 'DEVID='+str(self.DEVID)+'&CMD='+str(CMD)+'&TAG1='+str(TAG1)+'&TAG2='+str(TAG2)+'&TAG3='+str(TAG3)+'&FORMATOUT=WAP'

    def syncServersTime(self):
        '''
        @同服务的时间到本地
        :return:
        '''
        print 'Sync Servers Time'
        try:
            print  'ReadTime'
            data = self.makeUrlCode("ReadTime")
            #print 'data'+ data
            self.httpInit()
            self.conn.request("POST",self.PublicPortUri,data,self.pulicHaders)#获取时间是在获取配置之前所以在公共服务器上获取
            #print self.pulicHaders
            result = self.conn.getresponse()
            if str(result.status) == '200':#获取时间成功
                ackData = result.read()
                print ackData
                #解析时间
                dateTmp = re.findall(r"\d+~\d+",ackData)#找到时间部分
                dateTmp1 = re.findall(r"\d\d",str(dateTmp))
                setDateStr = "date -s \""+ str(int(dateTmp1[0])+2000)+'-'+dateTmp1[1]\
                +'-'+dateTmp1[2]+' '+dateTmp1[3]+':' + dateTmp1[4]+':'+dateTmp1[5]+"\""
                print  setDateStr
                #这里需要设置时间，Linux的os的系统调用方式
                try:
                    os.system(setDateStr)
                except Exception,e:
                    print 'system not support set date'
                print 'get system date ok'
                self.httpClose()
                return True
            else:
                print 'get system date error'
                self.httpClose()
                return False
        except Exception,e:
            self.httpErrorProcess()
            return False

    def getDeviceInfo(self):
        '''
        @获取设备信息
        :return:
        '''
        '''
        print 'get device info'
        try:
            curSysTime = time.strftime("%Y%m%d%H%M%S")
            md5obj = hashlib.md5()
            md5obj.update(curSysTime+str(self.DEVID)+self.SIGNStr)
            sign = md5obj.hexdigest()
            #print 'MD5:',sign
            data = urllib.urlencode({'UID': self.UID, 'DEVID': self.DEVID,\
                                     'CMD':"GetDevInfor",'FORMATOUT':"json"})
            #print data
            #print self.pulicHaders
            self.httpRelink() #重新连接服务器
            self.conn.request("POST", self.PublicPortUri, data, self.pulicHaders)
            result = self.conn.getresponse()
            if str(result.status) == '200':#获取时间成功
                ackData = result.read()
                #print ackData
                jsonStr = json.loads(ackData)
                print jsonStr["data"][0]["serverName"]
                print jsonStr["data"][0]["authName"]
                print jsonStr["data"][0]["authPwd"]
                self.organ = jsonStr["data"][0]["serverName"]
                self.UID = jsonStr["data"][0]["authName"]
                self.PASS = jsonStr["data"][0]["authPwd"]
                host = "www." + str(self.organ)
                self.conn.close()
                self.conn = httplib.HTTPConnection(host)
                self.haders = {"Content-type": "application/x-www-form-urlencoded",
                               "Accept": "text/plain",
                               "host": str(self.organ),
                               "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
                               "Connection":"Keep - Alive"}
                print 'get device config info ok'
                return True
            else:
                print 'get device config info error'
                #self.httpRelink()
                return False
        except Exception,e:
            self.httpErrorProcess()
            return False
        '''
        pass
        return True

    def putFrameSever(self):
        '''
        上传一帧图片到服务器
        :return: ture 表示上传成功
                  false 表示上传失败
        '''
        if os.path.exists(self.RTDataFileNameBat) != True:
            print  '还没有生成照片文件'
            return False
        try:
            curSysTime = time.strftime("%Y%m%d%H%M%S")
            md5obj = hashlib.md5()
            md5obj.update(curSysTime+str(self.DEVID)+self.SIGNStr)
            sign = md5obj.hexdigest()
            reqUrl = 'http://'+self.organ+self.versionOldURL+'?'+"DEVID="+str(self.DEVID)+'&CMD=uploadPhoto'+'&TIMESTAMP='+str(curSysTime)+"&SIGN="+str(sign)

            postFile = [('PHOTO', ('test.jpg', open(parameter.systemPhotoFilePath,'rb'),'image/jpeg'))]
            response = requests.post(url = reqUrl,files=postFile)
            if int(response.status_code) == 200:
                print '>>>>>>>', response.text
                jsonStr = json.loads(response.text)
                return jsonStr["success"]
            else:
                print "上传照片失败",response.text
                return  False
        except Exception,e:
            print "上传照片程序运行异常"
            return False

    def askSeverNeedAction(self):
        '''
        询问服务器需要的动作，当前只需要询问是否拍照
        :return:
        '''
        try:
            curSysTime = time.strftime("%Y%m%d%H%M%S")
            md5obj = hashlib.md5()
            md5obj.update(curSysTime+str(self.DEVID)+self.SIGNStr)
            sign = md5obj.hexdigest()
            #print 'MD5:',sign
            data = urllib.urlencode({'DEVID': self.DEVID,\
                                     'CMD':"getNeedSubmitPhoto",'TIMESTAMP':curSysTime,'SIGN':sign})
            #print data
            #print self.pulicHaders
            self.httpRelink()
            self.conn.request("POST", self.versionOldURL, data, self.pulicHaders)
            result = self.conn.getresponse()
            if str(result.status) == '200':#获取时间成功
                ackData = result.read()
                #print ackData
                jsonStr = json.loads(ackData)
                print jsonStr["success"]
                if jsonStr["success"]:
                    print "askphoto",jsonStr["data"][0]["askphoto"]
                    return jsonStr["data"][0]["askphoto"]
                else:
                    print "sever return success status is False"
                    return False
            else:
                print 'get device config info error'
                return False
        except Exception,e:
            print "ask sever need submit photo run error !!!"
            return False

    def getLackList(self,num):
        '''
        获得冻结数据列表
        :return:
        '''
        try:
            tag1 = '00000000,'+str(num)
            print tag1
            data = self.makeUrlCode("GetLackList", TAG1=tag1)
            self.httpRelink()
            self.conn.request("POST", self.PublicPortUri, data, self.pulicHaders)
            result = self.conn.getresponse()
            if str(result.status) == '200':  # 获取时间成功
                print result.reason,result.status
                print 'get lack list ok'
                body = result.read()
                print body
                return body.split(';')[1:-1]
                #return True

            else:
                print 'get lack list error'
                # self.httpRelink()
                return False
        except Exception,e:
            print 'get lack list error'
            self.httpErrorProcess()
            return False

    def uploadFixData(self, TAG2):
        '''
        @上传冻结数据到服务器
        :param TAG2: 冻结数据的主要数据部分
        :return:
        '''
        try:
            data = self.makeUrlCode("PutLackInfor", TAG1=TAG2)
            self.httpRelink()
            self.conn.request("POST", self.PublicPortUri, data, self.pulicHaders)
            print data
            result = self.conn.getresponse()
            print 'status = ',result.status
            if str(result.status) == '200':  # 获取时间成功
                print result.reason
                print 'upload fix data ok'
                return True
            else:
                print 'upload fix data error'
                #self.httpRelink()
                return False
        except Exception,e:
            print 'upload fix data error'
            self.httpErrorProcess()
            return False

    def syncFixData(self,sysdata):
        '''
        @同步冻结数据
        1.下拉冻结数据列表
        2.在数据库提取冻结数据
        3.上传冻结数据
        :return:
        '''
        try:
            outtime = 30#最多检测30天
            while outtime:
                outtime -= 1
                lackList  = self.getLackList(24)
                if lackList == False:
                    return False
                lackLen = len(lackList)
                if lackLen == 0:
                    return False
                tag2 = ''
                for date in lackList:
                    print date,int(date[0:2]),'-',int(date[2:4])
                    FixStr = sysdata.getFixDataTag2(date[0:2], date[2:4], date[4:6], date[6:8])
                    if FixStr == False:
                        print 'fix data is new'
                        if tag2 != '':
                            print tag2
                            self.uploadFixData(tag2)
                        return False
                    #print FixStr
                    tag2 += FixStr
                #print tag2
                self.uploadFixData(tag2)
                if(lackList < 24):
                    break
        except Exception,e:
            print "update fix data fail"
            return False


    def uploadRTData(self, count, stay, status):
        '''
        @上传实时数据到服务器
        :param count: 实用为进入人数量
        :param stay: 实用为出去人数量
        :param status:
        :return:
        '''
        try:
            tag2 = str(self.DEVID) + '~' + str(count) + '~' + str(stay) + '~' + str(status)+ ';'
            print tag2
            data = self.makeUrlCode("PutRTInfor", TAG2=tag2)
            #print data
            self.httpRelink()
            self.conn.request("POST", self.PublicPortUri, data, self.pulicHaders)
            result = self.conn.getresponse()
            if str(result.status) == '200':  # 获取时间成功
                print 'uploade RT data ok'
                return True
            else:
                print 'uploade RT data error'
                return False
        except Exception,e:
            print 'uploade RT data error'
            self.httpErrorProcess()
            return False

    def getDevArg(self):
        '''
        @获取设备参数，主要指安装高度等级、计数线位置、以及是否拍照的标志
        :return:
        '''
        try:
            curSysTime = time.strftime("%Y%m%d%H%M%S")
            md5obj = hashlib.md5()
            md5obj.update(curSysTime+str(self.DEVID)+"mdheda8c1c5asd478as3a2sd3")
            sign = md5obj.hexdigest()
            #print 'MD5:',sign
            data = urllib.urlencode({'DEVID': self.DEVID,\
                                     'CMD':"GetDevInfor","FORMATOUT":"WAP"})
            #print data
            self.httpRelink()
            self.conn.request("POST", self.PublicPortUri, data, self.pulicHaders)
            result = self.conn.getresponse()
            if str(result.status) == '200':#获取设备参数成功
                ackData = result.read()

                ackData = ackData.replace("\r\n","")
                #print ackData
                dateTmp = re.findall(r".*\{(.*)\}.*",ackData)#找到时间部分
                #print  dateTmp
                dateTmp1 = '{'+str(dateTmp[0])+'}'
                #dateTmp = dateTmp.replace('[\'','{')
                #dateTmp1 = dateTmp.replace('\']','}')
                #print  dateTmp1

                jsonStr = json.loads(dateTmp1)#解析json
                #print "devid",jsonStr["devid"]
                area_y1 = 0.4375
                area_y2 = 0.625
                area_x1 = 0
                area_x2 = 1
                highlevel = 2
                askphoto = False
                if int(jsonStr["devid"]) == int(self.DEVID):
                    area_y1 = float(jsonStr['area_y1'])
                    area_y2 = float(jsonStr['area_y2'])
                    area_x1 = float(jsonStr['area_x1'])
                    area_x2 = float(jsonStr['area_x2'])
                    highlevel = int(jsonStr['highlevel'])
                    askphoto = jsonStr['askphoto']
                else:
                    print "msg",jsonStr["msg"]
                    return False

                return (area_y1,area_y2,area_x1,area_x2,highlevel,askphoto)
            else:
                print "获取设备参数报文发送失败"
                self.httpErrorProcess()
                return False
        except Exception,e:
            print "获取设备参数运行异常"
            self.httpErrorProcess()
            return False

    def askSubmitPhoto(self):
        '''
        @询问服务器是否需要设备拍照
        :return:
        '''
        try:
            pass
        except Exception,e:
            print "查询是否需要进行拍照运行异常"

    def uploadPhoto(self):
        '''
        @上传照片到服务器
        :return:
        '''
        try:
            pass
        except Exception,e:
            print "上传照片运行异常"
########################################################################################################################

def loadDeviceHWInfo():
    '''
    @获取设备的硬件信息
    :return:
    '''
    f1 = open('/media/boot/deviceConfig.flw')
    data = pickle.load(f1)
    f1.close()

    return data['Mac'],data['Public']

def updateSystemDate(year,mon,day,hour,min,sec):
    '''
    @更新系统的日期
    :param year: 年
    :param mon: 月
    :param day: 日
    :param hour: 时
    :param min: 分
    :param sec: 秒
    :return:
    '''
    setDateStr = "date -s \"" + str(year + 2000) \
                 + '-' + str(mon) \
                 + '-' + str(day)\
                 + ' ' + str(hour) \
                 + ':' + str(min)\
                 + ':' + str(sec) + "\""
    os.system(setDateStr)
    os.system("date")

def getSystemDate():
    '''
    @获取系统日期
    :return: 年 月 日 时 分 秒
    '''
    date = time.localtime(time.time())
    return date.tm_year,date.tm_mon,date.tm_mday,date.tm_hour,date.tm_min,date.tm_sec

def strDateCompare(date1,date2):
    '''
    @比较两个字符串时间
    :param date1:
    :param date2:
    :return: Trun
    '''
    localtime1 = time.strptime(date1,'%y%m%d%H%M%S')
    localtime2 = time.strptime(date2,'%y%m%d%H%M%S')

    time1 = time.mktime(localtime1)
    time2 = time.mktime(localtime2)
    #print time1-time2
    return time1 - time2

class devSysemData():
    '''
    #体验数据的处理类
    #冻结数据存储格式如下
    0    1    2   3   4    5    6    7
    flag year mon mday hour cnt time status
    #冻结数据0分钟类生成，1分钟后才可再次生成
    #冻结数据定位公式
    pos = (date[2]-1)*24+date[3] #其中pos表示偏移量，date[2]为日期date[3]为小时
    #不采用arg.arg.arg是因为这样会出错
    '''
    FixDataFileName = "./FixData.pkl"
    FixDataFileNameBat = "./FixData.bat"
    RTDataFileName = "./RTData.pkl"
    RTDataFileNameBat = "./RTData.bat"

    def __init__(self):
        self.sysTime = getSystemDate()
        #用于实时数据
        self.inNum = 0#进入人数
        self.outNum = 0#出去人数
        self.frameSpeed = 0#帧速度
        #用于精确人数统计
        self.preciseInSum = 0 #精确 进入 的总数据
        self.preciseOutSum = 0 #精确 出去 的总数据
        self.precisePedNum = 0
        #用于冻结数据
        self.FixMakeFlag = 0
        self.FixData = [[0] * 8 for row in range(745)]

    def setName(self,name):
        self.name = name

    def getName(self,name):
        return self.name
    def getPrecisePedNum(self):
        pedNum = self.preciseInSum - self.preciseOutSum
        if abs(pedNum):#如果表示进出人数之差
            if self.precisePedNum < pedNum:
                self.precisePedNum = pedNum
        return self.precisePedNum

    def __getSysRTDataCRC(self,data):
        crc = 0
        for i in data:
            crc += i
        return crc

    def __checkSysRTDataCRC(self):
        tmpdata = set()
        if os.path.exists(self.RTDataFileName):#加载原始的系统参数
            print 'load rt data start'
            try:
                f1 = open(self.RTDataFileName,'rb')
                tmpdata = pickle.load(f1)
                f1.close()
                if self.__getSysRTDataCRC(tmpdata[:-1]) == tmpdata[-1]:
                    print 'load sys RT data ok'
                    (self.preciseInSum, self.preciseOutSum, self.frameSpeed, year, mon, day, hour, min, sec) = tmpdata[:-1]
                    self.sysTime = ( year, mon, day, hour, min, sec)
                    curDate = getSystemDate()
                    if curDate[1] != mon or curDate[2] != day:#当读出的时间与当前时间不是在同一天时实时数据清零
                        self.preciseInSum = 0
                        self.preciseOutSum = 0
                    return 0
                else:
                    print 'load sys RT data error'
                    os.remove(self.RTDataFileName)
                    return -1
            except Exception,e:
                print "load rt data fail",Exception,e
                os.remove(self.RTDataFileName)
                print 'remove RT Data'

                return -1
        elif os.path.exists(self.RTDataFileNameBat):
            print 'load rt bat data start'
            try:
                f1 = open(self.RTDataFileNameBat,'rb')
                tmpdata = pickle.load(f1)
                f1.close()
                if self.__getSysRTDataCRC(tmpdata[:-1]) == tmpdata[-1]:
                    print 'load sys RT bat data ok'
                    (self.inNum, self.outNum, self.frameSpeed, year, mon, day, hour, min, sec) = tmpdata[:-1]
                    self.sysTime = (year, mon, day, hour, min, sec)
                    shutil.copy(self.RTDataFileNameBat,self.RTDataFileName)
                    return 0
                else:
                    print 'load sys RT bat data error'
                    os.remove(self.RTDataFileNameBat)
                    return -1
            except Exception,e:
                print Exception,e
                os.remove(self.RTDataFileNameBat)
                return -1
        else:#新设备
            return 1

    def __getFixDataCRC(self,fix):
        '''
        @获取冻结数据的CRC
        :return:
        '''
        crc = 0
        for i in fix:
            crc += int(i[3])+int(i[4])
        return crc

    def __checkFixDataCRC(self):
        '''
        @加载并检测CRC
        :return:
        '''
        tmpdata = set()
        if os.path.exists(self.FixDataFileName):
            print "load fix data start"
            try:#尝试加载冻结数据文件
                f1 = open(self.FixDataFileName,'rb')
                tmpdata = pickle.load(f1)
                f1.close()
                if(self.__getFixDataCRC(tmpdata) == tmpdata[744][0]):
                    print 'load fix data ok'
                    self.FixData = tmpdata
                    return  0
                else:
                    print 'load fix data error'
                    os.remove(self.FixDataFileName)
                    return -1
            except Exception,e:#如果加载文件失败
                print Exception,e
                os.remove(self.FixDataFileName)#删除这个损坏的文件
                return -1

        elif os.path.exists(self.FixDataFileNameBat):
            print 'load bat file start'
            try:
                f2 = open(self.FixDataFileNameBat,'rb')
                tmpdata = pickle.load(f2)
                f2.close()
                print 'load bat file end'

                if (self.__getFixDataCRC(tmpdata) == tmpdata[744][0]):
                    print 'bat crc check ok'
                    self.FixData = tmpdata
                    return 0
                else:
                    print 'bat crc check error'
                    os.remove(self.FixDataFileNameBat)
                    return -1
            except Exception,e:
                print Exception,e
                os.remove(self.FixDataFileNameBat)
                return -1
        else: #新设备
            return 1 #新设备刚刚开始工作

    def showFixData(self):
        for fix in self.FixData:
            if fix[0] == 0xaa:
                print fix[0],'-',fix[1],'-',fix[2],'-',fix[3],'-',fix[4],'-',fix[5],'-',fix[6],'-',fix[7]

    def makeFixData(self):
        '''
        @产生冻结数据
        :return: True 表示生成了新的冻结数据， False 表示没有新的冻结数据生成。
        '''
        date = getSystemDate()
        if(date[4] == 59) and (int(date[5]) >= 55) and (self.FixMakeFlag == 1):
            self.FixMakeFlag = 2
            pos = (date[2]-1)*24+date[3]
            self.FixData[pos][0] = 0xaa #flag
            self.FixData[pos][1] = (date[0]-2000) #cur year
            self.FixData[pos][2] = date[1] #cur mon
            self.FixData[pos][3] = date[2] #cur day
            self.FixData[pos][4] = date[3] #cur hour
            self.FixData[pos][5] = self.inNum #cur fix cnt
            self.FixData[pos][6] = self.outNum #cur fix time 这里客流系统中当作出数据
            self.FixData[pos][7] = self.frameSpeed #cur fix  status

            self.showFixData()
            self.inNum = 0
            self.outNum = 0
            self.saveFixData()
            self.saveRTData()
            if date[3] == 23:#每天23点将实时数据清零
                self.preciseInSum = 0
                self.preciseOutSum = 0
            return True
        else:
            return False

    def resartFixDataProcess(self):
        '''
        @重启后对冻结数据与实时数据的处理
        :return:
        '''
        s_year, s_mon, s_day, s_hour, s_min, s_sec = self.sysTime#shutdown 关机时间
        year,mon,day,hour,min,sec = getSystemDate()#当前系统时间
        if s_year < 2016:
            print 'Before any Shutdown system date is error'
            return False
        if year < 2016:
            print 'system power down ,now system date error,try recover'
            updateSystemDate(s_year, s_mon, s_day, s_hour, s_min, s_sec)
        print s_hour, hour, s_mon, mon, s_day, day, s_hour, hour, s_min, min, s_sec, sec

        #如果关机时间与当前时间不是同一天 或者不同 一个月 或者不同时
        if  s_day != day or s_mon != mon or s_hour != hour:
            pos = (s_day - 1) * 24 + s_hour
            self.FixData[pos][0] = 0xaa  # flag
            self.FixData[pos][1] = (s_year - 2000)  # cur year
            self.FixData[pos][2] = s_mon  # cur mon
            self.FixData[pos][3] = s_day  # cur day
            self.FixData[pos][4] = s_hour  # cur hour
            self.FixData[pos][5] = self.inNum  # cur fix cnt
            self.FixData[pos][6] = self.outNum  # cur fix time 这里客流系统中当作出数据
            self.FixData[pos][7] = self.frameSpeed  # cur fix  status

            #保存冻结数据
            self.saveFixData()
            self.showFixData()
            self.inNum = 0
            self.outNum = 0
            self.saveRTData()

    def checkMakeFixDataPorcess(self):
        '''
        @检查冻结是否需要生成
        '''
        date = getSystemDate()
        if (date[4] == 59) and (date[5] >= 55)and (self.FixMakeFlag == 0):
            self.FixMakeFlag = 1
            return True
        elif (date[4] >= 1 and date[4] < 10) and (self.FixMakeFlag == 2):#一分钟后才检测下一次冻结
            self.FixMakeFlag = 0
        return False

    def getHourFixData(self,year,mon,day,hour):
        '''
        @获取某一个小时(hour)的冻结数据
        :param self: obj
        :param year: 年
        :param mon: 月
        :param day: 日
        :param hour: 时
        :return: 冻结数据内容
        '''
        pos = (day-1)*24+hour
        return self.FixData[pos]

    def getFixDataTag2(self,year,mon,day,hour):
        #获取日期比当前日期还新
        nowDate = time.strftime("%y%m%d%H", time.localtime())+'0000'
        fixDate = str(year)+str(mon)+str(day)+str(hour)+'0000'
        #print nowDate,'---',fixDate
        if int(strDateCompare(fixDate,nowDate)) >= 0:
            #冻结数据还没有生成因此下面的数据都不需要在上传了
            return False
        pos = (int(day) - 1) * 24 + int(hour)
        #print 'pos',pos,int(day),int(hour)
        fix = self.FixData[int(pos)]
        if fix[2] == int(mon) and fix[3] == int(day) and fix[4] == int(hour):
            fixstr = '{:02d}'.format(fix[1])#年
            fixstr += '{:02d}'.format(fix[2])#月
            fixstr += '{:02d}'.format(fix[3])#日
            fixstr += '~'
            fixstr += '{:02d}'.format(fix[4])#时
            fixstr += '~'
            fixstr += '{:02d}'.format(fix[5])#in
            fixstr += '~'
            fixstr += '{:02d}'.format(fix[6])#out
            fixstr += '~'
            fixstr += '{:02d}'.format(fix[7])#speed
            fixstr += ';'
            return fixstr
        else:
            fixstr = str(year)+str(mon)+str(day)+'~'+str(hour)+'~'+'0~0~0;'
            return fixstr

    def saveFixData(self):
        '''
        @腌制冻结数据到文件系统中，防止掉电丢失
        :param self:
        :return:
        '''
        try:
            self.FixData[744][0] = self.__getFixDataCRC(self.FixData)
            #listb = pickle.dumps(self.FixData)
            #更新备份文件
            f1 = open(self.FixDataFileNameBat, 'wb')
            pickle.dump(self.FixData, f1, True)
            f1.close()
            #更新数据文件
            f2 = open(self.FixDataFileName, 'wb')
            pickle.dump(self.FixData, f2, True)
            f2.close()
            return True
        except Exception,e:
            return False

    def saveRTData(self):
        try:
            self.sysTime = getSystemDate()
            year, mon, day, hour, min, sec = self.sysTime
            data = (self.preciseInSum, self.preciseOutSum, self.frameSpeed, year, mon, day, hour, min, sec)
            crc = self.__getSysRTDataCRC(data)
            data = (self.preciseInSum, self.preciseOutSum, self.frameSpeed, year, mon, day, hour, min, sec, crc)
            # 更新备份文件
            f1 = open(self.RTDataFileNameBat, 'wb')
            pickle.dump(data, f1, True)
            f1.close()
            # 更新数据文件
            f2 = open(self.RTDataFileName, 'wb')
            pickle.dump(data, f2, True)
            f2.close()
            return True
        except Exception,e:
            return False

    def loadRTData(self):
        result = self.__checkSysRTDataCRC()
        if result == 0:#加载系统数据成功
            print 'Raw load sys rt data ok'
            return True
        elif result == -1:#加载原始数据失败尝试加载备份数据
            result = self.__checkSysRTDataCRC()#加载备份文件
            if result == 0:
                print 'BAT load sys rt data ok'
                return True
            else:
                return False
        elif result == 1:#新设备
            print 'this new device'
            return True

    def showSysRTData(self):
        print 'in  Num',self.inNum
        print 'out Num',self.outNum
        print 'frame Speed',self.frameSpeed
        print 'shutdown Time',self.sysTime

    def loadFixData(self):
        '''
        @加载冻结数据
        :param self:
        :return:
        '''
        result = self.__checkFixDataCRC()
        if result == 0:
            print "RAW load fix data ok"
            return True
        elif result == -1:
            result = self.__checkFixDataCRC()
            if result == 0:
                print 'BAT load fix data ok'
                return True
            else:
                return False
        elif result == 1:#新设备
            print 'this new device'
            return True


updateQueue = Queue.Queue(30)#缓存30条报文
mailQueue = Queue.Queue(30)#缓存30条报文

def local_data_thread(arg1,arg2):
    '''
    @处理device上冻结数据、实时数据、系统时间等信息
    :param arg1:
    :param arg2:
    :return:
    '''
    while True:
        try:
            if arg1.qsize() > 0 :
                #print 'qsize=',arg1.qsize()
                pedIn, pedOut, speed = arg1.get(block=False)
                if pedOut != 0 or pedIn != 0:#有人进或者有人出
                    #实时数据
                    arg2.inNum += pedIn
                    arg2.outNum += pedOut
                    #当日客流计数
                    arg2.preciseInSum += pedIn
                    arg2.preciseOutSum += pedOut
                    #帧数了
                    arg2.frameSpeed = speed
                    try:
                        arg2.saveRTData()
                        updateQueue.put(1,block=False)#更新实时数据
                    except Exception,e:
                        print 'save rt data error'
                print 'cur In:', pedIn, 'cur Out:', pedOut, 'Frame Speed:', speed, '>>>', '5 Minute RT','In:', arg2.inNum, 'Out:', arg2.outNum, \
                    'precise', 'in', arg2.preciseInSum, 'out', arg2.preciseOutSum
            else:
                result = arg2.checkMakeFixDataPorcess()
                if result == True:#有冻结数据产生
                    print 'make fix data'
                    try:
                        updateQueue.put(1,block=False)#上传一次实时数据
                    except Exception,e:
                        print "Put RT queue Full"
                    result = arg2.makeFixData()  # 产生冻结数据处理
                    time.sleep(0.01)
                    if result == True:
                        try:
                            updateQueue.put(2,block=False)#更新最新冻结数据
                        except Exception,e:
                            print "Put Fix Queue Full"
                    time.sleep(0.4)
        except Exception,e:
            print Exception,e,"local_data_thread run error"
        time.sleep(0.4)

def updateRTTimerProcess(cnt):
    cnt[0] += 1
    if cnt[0] % 30 == 0:
        try:
            updateQueue.put(1,0)#更新实时数据
        except Exception,e:
            print "RT Timer update process error"

def updateFixTimerProcess(cnt):
    cnt[1] += 1
    if cnt[1] % 360 == 0:
        try:
            updateQueue.put(2,0)#更新冻结数据
        except Exception,e:
            print "Fix Timer update process error"

def updatePhotoTimerProcess(cnt):
    cnt[2] += 1
    global askPhotoCnt

    T = 1
    askPhotoCnt += 1
    if askPhotoCnt > 20:
        T = 2
    elif askPhotoCnt > 50:
        T = 3
    elif askPhotoCnt > 60:
        T = 6
        askPhotoCnt == 60

    if cnt[2] % T == 0:
        global photoSaveFlag
        photoSaveFlag = True
        try:
            updateQueue.put(3,0)#更新拍照检测
        except Exception,e:
            print "Photo Update Timer Prcess error !!!"

def checkNetStatusTimerProcess(cnt):
    cnt[3] += 1
    global checkNetFlag

    if renetlink.systemNetWorkGet() == True:
        if cnt[3] % 720 == 0:
            checkNetFlag = True
    else:
        if cnt[3] % 20 == 0:
            checkNetFlag = True

def noRealTime_process(arg):
    '''
    实时性要求不高的处理线程
    :param arg:
    :return:
    '''
    global checkNetFlag
    while True:
        if checkNetFlag == True:
            #checkNetFlag = False
            try:
                if renetlink.systemNetStatusProcess() == 0:
                   checkNetFlag = False
            except Exception,e:
                print 'check system net status process error'
        time.sleep(1)

def updateDeviceArgTimerProcess(cnt):
    cnt[4] += 1
    if cnt[4] % 3 == 0:
        try:
            updateQueue.put(4,0)#更新设备参数
        except Exception,e:
            print "Device arg timer update process error!!!"

def updateTimerThread(arg1):
    '''
    @定时更新计数线程
    :param arg1:
    :return:
    '''
    updateCnt =  [4,0,1,0,0]
    while True:
        time.sleep(10)
        updateFixTimerProcess(updateCnt)
        updateRTTimerProcess(updateCnt)
        updatePhotoTimerProcess(updateCnt)
        updateDeviceArgTimerProcess(updateCnt)
        checkNetStatusTimerProcess(updateCnt)

def askServerActionProcess(comm):
    '''
    询问服务需要执行什么动作，目前只询问拍照询问结果为True拍照
    :return:
    '''
    result =  comm.askSeverNeedAction()
    if result:
        global askPhotoCnt
        askPhotoCnt = 1
        print "需要拍照上传到服务器"
        comm.putFrameSever()

def updateDeviceArgProcess(arg1,arg3):
    devarg = arg1.getDevArg()
    print "检测区域",devarg
    if devarg != False:
        #成功获取参数才修改参数配置文件
        if arg3.setDevArgs(devarg) == True:
            arg3.saveDevArg()
            os.system("reboot")

def update_data_thread(arg1,arg2,arg3):
    '''
    @更新数据线程
    :param arg1:协议栈
    :param arg2:本地数据
    :return:
    '''
    #检测系统更新

    print "Get Sever Time Start"
    #没有获取不到时间就一直获取，否则后期也无法正常工作
    while True:
        result = arg1.syncServersTime()#同步设备的时间
        if result == True:
            break
        print 'get server time fail'
        time.sleep(10)

    #获取配置信息不到后面无法工作所以一直获取
    while True:
        result = arg1.getDeviceInfo()#获取配置信息
        if result == True:
            break
        print 'get server config info fail'
        time.sleep(10)

    #获取设备参数
    updateDeviceArgProcess(arg1,arg3)

    arg2.resartFixDataProcess()#恢复冻结数据
    arg1.syncFixData(arg2)#同步冻结数据
    arg1.uploadRTData(arg2.preciseInSum ,arg2.preciseOutSum,arg2.frameSpeed)#上传实时数据
    #askServerActionProcess(arg1)#拍照同步处理

    while True:
        if updateQueue.qsize() > 1:
            updateType = updateQueue.get()
            #print 'updateType',updateType#更新数据类型
            if renetlink.systemNetWorkGet() == True:#网络正常
                if updateType == 1:#上传实时数据
                    arg1.uploadRTData(arg2.preciseInSum ,arg2.preciseOutSum,arg2.frameSpeed)
                elif updateType == 2:#同步冻结数据
                    arg1.syncFixData(arg2)
                elif updateType == 3:#询问是否需要拍照
                    #askServerActionProcess(arg1)
                    pass
                elif updateType == 4:#更新设备参数效果
                    updateDeviceArgProcess(arg1,arg3)

        time.sleep(0.1)

import fcntl
def photoSave(frame):
    '''
    设置计数线需要的拍照
    :param frame:
    :return:
    '''
    f = open(parameter.systemPhotoFilePath, 'wb')
    fcntl.flock(f,fcntl.LOCK_EX)
    cv2.imwrite(parameter.systemPhotoFilePath,frame)
    fcntl.flock(f,fcntl.LOCK_UN)
    f.close()

def frame_hour_delay_process(arg):
    while True:
        if mailQueue.qsize() >= 1:
            emailFile = mailQueue.get(True)
            print "send mail ^_^",emailFile
            emailSend.smtplib_send_test_mail(emailFile)
        time.sleep(0.01)


def frame_result_process(arg1):
    '''
    @这是一个计数视频结果的录像视频
    :param arg1: 邮件
    :return:
    '''
    CreateRecordFile = True
    fourcc = cv2.VideoWriter_fourcc(*'XVID')#视频格式
    date = getSystemDate()
    out = cv2.VideoWriter('result/hour_'+str(date[3])+'.avi', fourcc, 30.0, (320,240))
    while True:
        date = getSystemDate()
        if (date[4] == 00) and (date[5] == 00):#整点小时和分钟数据都是0
            if (date[3] > 7) and (date[3] < 19):#时间段内能录像
                if CreateRecordFile == True:#需要创建录像文件
                    CreateRecordFile = False
                    out = cv2.VideoWriter('result/hour_'+str(date[3])+'.avi', fourcc, 30.0, (320,240))
                    try:
                        emailFile = 'result/hour_'+str(date[3]-1)+'.avi'
                        if date[3] == 8:
                            emailFile = 'result/hour_18.avi'
                        elif date[3] == 18:
                            emailFile = 'result/hour_8.avi'
                        print "send mail to user"
                        mailQueue.put(emailFile,block=False)
                        #emailSend.smtplib_send_test_mail(emailFile)
                    except Exception,e:
                        print "send debug mail error ！！！"
        else:
            CreateRecordFile = True #可以重新录像

        #elif (date[3] == 0) and (date[4] == 10) and (date[5] == 0):#0:10:0分钟系统自动重启
        #    os.system("reboot")

        if arg1.qsize() > 1:#列队大小
            frame,photo,recordFlag = arg1.get(True)
            if (date[3] > 7) and (date[3] < 19):#满足录像条件
                cv2.putText(frame, str(date[3])+':'+ str(date[4])+':'+str(date[5]), (130, 15), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1,
                            (10, 0, 10), 1, cv2.LINE_AA)
                if recordFlag == True:
                    out.write(frame)
                    #out.write(photo)

            #拍摄上传服务器的照片
            global photoSaveFlag
            if photoSaveFlag == True:
                photoSaveFlag = False
                photoSave(frame)
            #本地安装视频查看
            if parameter.UseingFlaskVideo == True:
                flaskVideo.putFrame(frame)#输出结果到web
        time.sleep(0.01)

def saveStrToFile(filename, contents):
    fh = open(filename, 'wb')
    fh.write(contents)
    fh.close()

import socket,sys
def configSystemNetProcess(arg1):
    while True:
        server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        server.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
        server.bind(('',8800))
        while True:
            try:
                print  'test'
                data,addr = server.recvfrom(1024)
                print 'data from',addr
                print data
                if is_json(data) == True:
                    jsonStr = json.loads(data)
                    if jsonStr['cmd'] == 'SetWifiParamReq':#设置WIFI参数请求
                        print '设置WIFI参数'
                        print jsonStr['data']['ssid']
                        print jsonStr['data']['key']
                        ssid = jsonStr['data']['ssid']
                        pwd = jsonStr['data']['key']

                        #更新配置文件
                        netConfigFile = "auto lo\n" \
                                        "iface lo inet loopback\n" \
                                        "source-directory /etc/network/interfaces.d\n" \
                                        "auto wlan1\n" \
                                        "iface wlan1 inet dhcp \n" \
                                        "wpa-ssid "+str(ssid)+"\n" \
                                        "wpa-psk "+str(pwd)+"\n"
                        print netConfigFile
                        saveStrToFile("/etc/network/interfaces",netConfigFile)

                        sendData = {'cmd':'SetWifiParamAck','result':'ok','data':str(arg1.DEVID),'date':jsonStr['date']}
                        jdict = json.dumps(sendData)
                        server.sendto(jdict,addr)
                        os.system("killall hostapd")
                        os.system("killall dnsmasq")
                        os.system("/etc/init.d/networking restart")
                        #os.system("udhcpc -i ifconfig | grep  \"Link\" | awk '{print $1}' | grep \"wlan\"")
                        os.system("killall udhcpc;udhcpc -i wlan1 -n")

                else:
                    print '收到的数据不是字符串'
            except Exception,e:
                print "配置系统网络处理异常"
            #time.sleep(1)

def init(arg1,arg2,arg3):
    '''
    @业务处理初始化函数
    :param arg1:
    :param arg2:
    :param arg3: 安装高度更新通知邮件
    :param arg4: 计数区域更新通知邮件
    :return:
    '''
    print 'CPU process start'

    thread4 = threading.Thread(target=frame_result_process, args=(arg2,))
    thread4.setDaemon(True)#设置守护进程
    thread4.start()

    devMac = 66661
    devPublicUrl = '106.14.199.92'
    if platform.system() != "Windows":
        devMac, devPublicUrl = loadDeviceHWInfo()

    data = devSysemData()#创建系统数据对象
    data.loadFixData()#加载数据
    data.loadRTData()#加载实时数据
    data.showSysRTData()#显示实时数据
    data.showFixData()#显示冻结数据
    time.sleep(1)
    comm = Protocol(devMac, url=devPublicUrl)#创建通信协议
    comm.httpInit()

    threads = []

    #本地数据处理
    thread1 = threading.Thread(target=local_data_thread, args=(arg1,data))
    threads.append(thread1)

    #数据更新处理线程
    thread2 = threading.Thread(target=update_data_thread, args=(comm,data,arg3))
    threads.append(thread2)

    #更新计时器
    thread3 = threading.Thread(target=updateTimerThread, args=(None,))
    threads.append(thread3)

    #非实时处理
    thread5 = threading.Thread(target=noRealTime_process, args=(None,))
    threads.append(thread5)

    #配置系统网络处理
    thread6 = threading.Thread(target=configSystemNetProcess, args=(comm,))
    threads.append(thread6)

    #整点延时任务处理
    thread7 = threading.Thread(target=frame_hour_delay_process, args=(None,))
    threads.append(thread7)
    for t in threads:
        t.setDaemon(True)
        t.start()
    print 'CPU4 Process end'